package com.clp.protocol.modbus_tcp.connect.state;

import com.clp.protocol.core.common.async.IPromise;
import com.clp.protocol.core.exception.EnumElemDoesNotExistException;
import com.clp.protocol.modbus_tcp.connect.ConnInfoImpl;
import com.clp.protocol.modbus_tcp.connect.config.ConnConfig;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;

import java.util.Arrays;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 连接状态：所有的连接状态互不干扰
 *  在发送帧时，先更新主站状态，再更新连接状态。
 *  在接收帧时，先更新连接状态，再更新主站状态。
 */
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class ConnState extends AbstractState {

    public enum Type {
        ;

        public ConnState newConnState(ConnInfoImpl connInfoImpl, ConnConfig cfg) {
            throw new EnumElemDoesNotExistException(Type.class);
        }
    }

    public abstract Type type();

    protected final ConnInfoImpl connInfoImpl;

    public abstract  <V> IPromise<V, ?> register(IPromise<V, ?> sendPromise);

    @Override
    protected ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit) {
        return connInfoImpl.channel().eventLoop().scheduleAtFixedRate(task, initialDelay, period, unit);
    }

    public static ConcurrentMap<Type, ConnState> newConnStateMap(ConnInfoImpl connInfoImpl, ConnConfig cfg) {
        return Arrays.stream(Type.values())
                .collect(Collectors.toConcurrentMap(type -> type, type -> type.newConnState(connInfoImpl, cfg)));
    }
}
